package com.pavco.caribbeanvisit.client.ui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.NodeList;
import com.google.gwt.xml.client.XMLParser;
import com.pavco.caribbeanvisit.client.RpcService;
import com.pavco.caribbeanvisit.client.RpcServiceAsync;
import com.pavco.caribbeanvisit.client.MyResources;
import com.pavco.caribbeanvisit.client.event.ReceivedXmlEvent;
import com.pavco.caribbeanvisit.client.eventhandlers.ReceivedXmlEventHandler;
import com.pavco.caribbeanvisit.shared.models.Country;

public class MarkerSlideShow extends Composite {
  HandlerManager eventBus;

  private static MarkerSlideShowUiBinder uiBinder = GWT
      .create(MarkerSlideShowUiBinder.class);

  interface MarkerSlideShowUiBinder extends
      UiBinder<Widget, MarkerSlideShow> {
  }

  @UiField HTML imageTitle;
  @UiField HTML prev;
  @UiField HTML next;
  @UiField HTML albumTitle;
  @UiField DecoratorPanel centrePanel;
  @UiField TableRowElement imageRow;
  @UiField TableCellElement imageCell;

  private Country country;
  private final Image centreImg = new Image();
  private ArrayList<Photo> photoList = new ArrayList<Photo>();
  private int currentPhotoIndex = 0;
  private HashMap<Photo, Image> photoImageMap = 
      new HashMap<Photo, Image>();
  
  /**
   * Create a remote service proxy to talk to the server-side Country service.
   */
  private final RpcServiceAsync genericService = GWT
      .create(RpcService.class);
  
  public MarkerSlideShow(Country country, HandlerManager eventBus) {
    initWidget(uiBinder.createAndBindUi(this));
    prev.setHTML("&lt;");
    next.setHTML("&gt;");
    imageRow.setAttribute("height", "180px");
    imageCell.setAttribute("width", "200px");
    centreImg.setUrl(MyResources.INSTANCE.loading().getURL());
    applyStyles();
    this.country = country;
    this.eventBus = eventBus;
    this.albumTitle.setHTML(country.getName());
    listenToReceivedXmlEvent();
  }

  private void listenToReceivedXmlEvent() {
    eventBus.addHandler(ReceivedXmlEvent.TYPE, new ReceivedXmlEventHandler() {
      
      @Override
      public void onReceivedXml(ReceivedXmlEvent event) {
        if (null == event.getData()) {
          noPhoto();
          return;
        }
        Document doc = XMLParser.parse(event.getData());
        NodeList entryElements = doc.getElementsByTagName("entry");
        for (int i = 0; i < entryElements.getLength(); ++i) {
          Photo p = new Photo();
          Element entry = (Element) entryElements.item(i);
          Element content = (Element) entry.getElementsByTagName("content").item(0);
          p.setTitle(getElementTextValue(entry, "summary"));
          p.setUrl(getElementAttrTextValue(content, "src"));
          photoList.add(p);
        }
        if (centrePanel.getWidget() != null) {
          centrePanel.remove(centrePanel.getWidget());
        }
        if (1 > photoList.size()) {
          noPhoto();
          return;
        }
        Photo p = photoList.get(0);
        imageTitle.setHTML(p.getTitle());
        centreImg.setUrl(p.getUrl());
        centrePanel.add(centreImg);
      }
    });
  }
  
  private void noPhoto() {
    centreImg.setResource(MyResources.INSTANCE.naImageSm());
    imageTitle.setHTML("Image not available");
  }

  private void applyStyles() {
    centrePanel.setHeight("100px");
    next.addStyleName("nextPrevButton");
    prev.addStyleName("nextPrevButton");
  }
  
  @UiHandler({"next", "prev"})
  void doClick(ClickEvent event) {
    Widget sender = (Widget) event.getSource();          
    if (sender == next) {
      if (currentPhotoIndex < photoList.size() - 1) {
        ++currentPhotoIndex;
      } else {
        return;
      }
      Photo p = photoList.get(currentPhotoIndex);
      Set<Photo> photoSet = photoImageMap.keySet();
      centrePanel.clear();
      if (!photoSet.contains(p)) {
        photoImageMap.put(p, new Image(p.getUrl()));
      }
      centrePanel.clear();
      centrePanel.add(photoImageMap.get(p));
      imageTitle.setHTML(p.getTitle());
      
      // Now load next image if there is one
      int nextPhotoIndex = currentPhotoIndex + 1;
      if (nextPhotoIndex < photoList.size()) {
        Photo p2 = photoList.get(nextPhotoIndex);
        if (!photoSet.contains(p2)) {
          photoImageMap.put(p2, new Image(p2.getUrl()));
        }
      }
    } else if (sender == prev) {
      if (currentPhotoIndex > 0) {
        --currentPhotoIndex;
      } else {
        return;
      }
      Photo p = photoList.get(currentPhotoIndex);
      Set<Photo> photoSet = photoImageMap.keySet();
      centrePanel.clear();
      if (!photoSet.contains(p)) {
        photoImageMap.put(p, new Image(p.getUrl()));
      }
      centrePanel.add(photoImageMap.get(p));
      imageTitle.setHTML(p.getTitle());
    }
  }
  
  /*private void requestFailed(Throwable exception) {
    Window.alert("Failed to send the message: "
        + exception.getMessage());
  }*/
  
  private String getElementTextValue(Element parent, String elementTag) {
    return parent.getElementsByTagName(elementTag).item(0).getFirstChild().getNodeValue();
  }
  
  private String getElementAttrTextValue(Element parent, String attrName) {
    return parent.getAttributes().getNamedItem(attrName).getNodeValue();
  }
  
  /**
   * Receives a list of photos using the Picasa GData REST specifications.
   * 
   * @param username User account name containing the album
   * @param albumName The album name
   * @return A list of Photos
   */
  public void load(String username) {
    String url = "http://picasaweb.google.com/data/feed/api/user/" + username + "/album/"
        + country.getName() + "?kind=photo&imgmax=200";
    genericService.getFeedFeed(url, new AsyncCallback<String>() {
      
      @Override
      public void onSuccess(String result) {
        ReceivedXmlEvent rXmlE = new ReceivedXmlEvent();
        rXmlE.setData(result);
        eventBus.fireEvent(rXmlE);
      }
      
      @Override
      public void onFailure(Throwable caught) {
        // TODO Auto-generated method stub
        
      }
    });
  }
  
  private class Photo {
    private String title;
    private String url;
    
    public String getTitle() {
      return title;
    }
    
    public void setTitle(String title) {
      this.title = title;
    }

    public String getUrl() {
      return url;
    }
    
    public void setUrl(String url) {
      this.url = url;
    }
  }
}